home *** CD-ROM | disk | FTP | other *** search
/ Commodore 64 Scene Diskmags Assortment / Commodore_CEE_Vol._1_Issue_05_1995_Jack_Vander_White_Disk_2_of_3_Side_B.d64 / program bit 6 < prev    next >
Text File  |  2023-02-26  |  15KB  |  247 lines

  1. Out of memory error in C64 BASIC
  2.  
  3. From: John Iannetta
  4.  
  5. Antony Lord writes:
  6.  
  7. >I was wondering what the 'Out of Memory Error In xxxx' error actually means. 
  8.  
  9. >I have a few hundred lines of BASIC code and while it is running it sometimes halts and I get a message such as 'Out of Memort Error in 7610' where 7610 IF (N<1) or (N>9) THEN GOTO 2342.
  10.  
  11.     An "?OUT OF MEMORY  ERROR IN nn" message using the C-64, has two general causes. One is that the address in 49, 50 (low byte, high byte) would be greater than the address in 51, 52 if the instruction were executed. Do a NEW, and then enter this BASIC program:
  12.  
  13. 10 poke55,70:poke56,8:clr 
  14. 20 a=1:printa 
  15. 30 b=2:printb 
  16. 40 c=3:printc
  17.  
  18. and run it. The number in 49, 50 starts off at 2103; the number in 51, 52 at 2118. Each time that a simple variable is defined, the first number increases by 7. If line 40 were executed, the first address would be greater than the second. To guard against such errors, make the first line of your BASIC program something like:
  19.  
  20. 10 poke55,0:poke56,160:clr
  21.  
  22.     The second general cause of such an error message is stack overflow. Page 1 (256 to 511) is used for the stack of the 6510 MPU. Return addresses of subroutines are stored their, as are return addresses of interrupts (along with the contents of the processor status register). Page 1 is also used by some BASIC arithmetic routines for storage of number strings. Type in (in direct mode):
  23.  
  24. ?2*50 <CR>
  25.  
  26. and then:
  27.  
  28. fori=1to3:?chr$(peek(256+i));:next <CR>
  29.  
  30. But BASIC also uses the stack for two other purposes: to store return addresses of GOSUB instructions, and for FOR-NEXT return addresses (along with other FOR-NEXT information). Each time that a GOSUB is called, data are pushed onto the stack (using up page 1 memory). When BASIC hits a RETURN, the data are pulled off the stack (freeing up the memory). If you do either a GOSUB or an ONvariableGOSUB, and end the subroutine with a GOTO rather than with a RETURN, you are in trouble. For each call, data are pushed onto the stack but not pulled off. Try running this:
  31.  
  32. 10 gosub20 
  33. 20 printa:a=a+1:goto10
  34.  
  35. After a dozen or two loops, there is no more stack room. Check to see that you didn't use GOSUB when you meant GOTO (or ON...GOSUB when you meant ON...GOTO). The same problem can arise with FOR-NEXT loops. The FOR statement pushes data onto the stack; if there is no corresponding NEXT, the free stack space is less. But that type of BASIC programming mistake is probably less common.
  36.  
  37. ---------------------------------- 
  38.  
  39. Recommended Assemblers.... 
  40.  
  41. From : judd@merle.acns.nwu.edu
  42.  
  43. Patrick Fleming <wiz@apple.com> wrote:
  44.  
  45. >I have a rather large assembly program (8000 lines) that I have been compiling on a PC using AS6502. I've never bothered to find a 64 assembler because I didn't feel it could handle source code of this length. A friend of >mine says it shouldn't be a problem. Has anyone any experience with large source files?  What assembler would you recommend?  I heard a lot about  Merlin, but can't find it on the net.
  46.  
  47. I don't know that it will help much, but I can tell you about Merlin. First, it is/was a commercial program. I haven't seen it for sale in any catalogs, but the author is Glen Bredon, who might still be around on GEnie or BIX or CS, and the publisher was
  48.  
  49.         Roger Wagner Publishing, Inc
  50.         10761 Woodside Avenue, Suite E
  51.         Santee, CA 92071
  52.         619-562-3670
  53.  
  54. Since I think Merlin is the greatest thing since sliced bread, I will take this opportunity ot extol its virtues. Yes, it can handle an 8000 line file, although maybe not all at once. For one thing, it can assemble directly to disk. There is also a pseudo-opcode "PUT" which essentially inserts a text file into your code, so that you can in essence assemble parts of the code at a time, without having to store all the code (and comments) in memory. But, neatest of all, Merlin has a linker, so that you could assemble different parts of the code into individual object files, and link them all together. Even better, of course, is that you don't have to keep re-assembling large pieces of code which work fine.
  55.  
  56. Neat!  So yes, it is possible to compile those huge files on a 64.
  57.  
  58. >I also have a 128, if anyone knows of a good assembler for it.
  59.  
  60. Merlin 128 :). Even works with my FD-2000 with no problem. I bought mine here a little over a year ago. Since I consider this one of mankind's greatest software achievements, I of course wish it were available comercially. Maybe CMD can pick it up.
  61.  
  62. Anyways, I guess this wasn't too helpful, but maybe RW is still around and you could give them a call.
  63.  
  64. -----------------
  65. assembly stuff
  66.  
  67. From : Rod Gasson
  68.  
  69.  -=> Quoting Steve Craik to Brian Green <=-
  70.  
  71.  BG>  to fill the first 256 bytes with 0's at 2048 it would be something like:
  72.  
  73.  C000   LDY #$00      ; Load the Y Register with the NUMBER 0
  74.  C003   LDA #$00      ; Load the Accumalator with the number 0
  75.  C006   STA $0800,Y   ; Store Y in the area $0800
  76.  C009   INY           ; Increase Y (Y=Y+1)
  77.  C00B   BNE $C006     ; Branch if not equal to 0 to $C006
  78.  C00E   RTS           ; Return to Subroutine
  79.  
  80.  SC> At first, I was wondering ..how would it stop at the 256'th address.  Then it dawned on me. Once you reach 255 (0-255 =256) it goes back to zero.
  81.  
  82. Yup.
  83.  
  84.  SC> Now, what about the case where we would want to fill more than 256 addresses with zero.
  85.  
  86. There's a few methods, for example, if you wish to fill 1k (1024 bytes) You could use
  87.  
  88.      C000   LDY #$00      ; Load the Y Register with the NUMBER 0
  89.      C003   LDA #$00      ; Load the Accumalator with the number 0
  90.      C006   STA $0800,Y   ; Store Y in the area $0800
  91.             STA $0900,Y
  92.             STA $0A00,Y
  93.             STA $0B00,Y
  94.             INY           ; Increase Y (Y=Y+1)
  95.             BNE $C006     ; Branch if not equal to 0 to $C006
  96.             RTS           ; Return to Subroutine
  97.  
  98. ------------------------------------ 
  99.  
  100. Sample 1x1 Scrolly Code
  101.  
  102. From: alstrup@diku.dk (Asger K. Alstrup Nielsen)
  103.  
  104. [part of a scroll-routine snipped here]
  105.  
  106. ;(if we don't introduce a delay, the text will scroll by WAY TOO FAST to READ ! !   Incredible, this 1 Mhz bugger machine of ours is, eh? delays not set in stone, play with them :)  higher, lower, etc... >
  107.  
  108. LDX #$05     ; just a delay loop - ldx counted down by dex >waitloop LDY #$FF     ; a delay loop within a delay loop wl2
  109. DEY          ; decrement y in our delay looop 
  110. BNE wl2      ; keep counting y down until y = 0
  111. DEX          ; decrement x in our top delay loop 
  112. BNE waitloop ; repeat the y loop until x = 0
  113.  
  114. [even more snipped here]
  115.  
  116. In the following, I'll descripe *very* basic features like the concepts of rasters and frames. This is probably only interesting for newcomers in the assembly-domain.
  117.  
  118. If you are looking for a smoother scroll, you would use what is commonly known as "rasters".
  119.  
  120. Your tv-set displays the image on the screen using an electron-beam which moves from the top, left corner down towards the lower, right corner in horizontal lines. If my memory serves my right, PAL (mostly  european) screens have 312 lines, while NTSC (in the USA) screens have  262 lines. We count these lines starting from 0, and call them  "raster-lines", or just "rasters".
  121.  
  122. The commodore 64 has a few registers in the VIC (the chip that generates the video-image) which reflect where the electron-beam is. We have one register at adress $D012 which contains the first 8 bits of the raster, and another at adress $D011, where bit 7 describes the 9th bit of the rastervalue. You can safely regard the rasterline as a Y-coordinate on the screen that starts from above and works its way down.
  123.  
  124. In this way, you can use this formula to obtain the rastervalue:
  125.  
  126.   raster= peek(53266)+ (peek(53265) and 128) * 2;
  127.  
  128. Note, that this isn't of much use in a basic-program because basic simply is too slow, and when the calculation is done, the rasterline has changed so much that the value of "raster" is more random than usefull.
  129.  
  130. Well, the value in $D012 goes from 0 to 255 while $D011 bit 7 is 0, refrecting that the rasterline goes from 0-255. Then bit 7 in $D011  is set to 1, and $D012 goes from 0 to 55 on a PAL-system, refrecting  that the rasterline is 256-311. This is what is know as a "frame", and the cycle starts over with $D012 being 0, and bit 7 in $D011 also being 0.
  131.  
  132. You can exploit this register to get a smooth scroll in several ways. I'll describe the most primitive of these techniques in the following.
  133.  
  134. A smooth scroll is achieved, if the text is moved every frame, not more, not less. In other words, the delay loop in the scroll should be adjusted so that the entire scroll-loop is performed exactly once per frame.
  135.  
  136. Okay, that's fine, but how do I achieve this?
  137.  
  138. You simply monitor the rasterline. A simple way of doing this is to use a bit of code like this, which waits until the rasterline is at position 0 exactly.
  139.  
  140. wait    lda $d012       ;Wait until the lower bits of the rastervalue
  141.         cmp #0          ;is 0.
  142.         bne wait
  143.  
  144.         lda $d011       ;We also need to check if the high bit of
  145.         and #$80        ;the rastervalue is 0, in order to destinguish
  146.         bne wait        ;raster 0 from raster 256.
  147.  
  148. Another, slighty optimized version, could be:
  149.  
  150.         lda #$ff wait    cmp $d012
  151.         bne wait
  152.  
  153. which waits until the rasterline is $ff. This one exploits the fact that the rasterline never exceeds 311, so $d011 bit 7 will always be 0, when $d012 is >55.
  154.  
  155. You should try to play around with such wait-loops, and with a little effort you should be able to do a smooth scroll.
  156.  
  157. You can also try to use $d020 to set the border-color at different rasterlines, like:
  158.  
  159. wait1   lda $d012       ;Wait for rasterline $30
  160.         cmp #$30
  161.         bne wait1
  162.         lda $d011
  163.         bmi wait1
  164.  
  165.         lda #1          ;Set border-color to white
  166.         sta $d020
  167.  
  168. wait2   lda $d012       ;Wait for rasterline $108
  169.         cmp #$08        
  170.         bne wait2
  171.  
  172.         lda #0          ;Set border-color to black
  173.         sta $d020
  174.  
  175.         jmp wait1       ;And keep looping
  176.  
  177. Notice that the second wait-loop exploits that the next time $d012 will be $08 after rasterline $30, will be at rasterline $108, which makes a check on $d011 un- nescessary.
  178.  
  179. This little program will produce a white stripe in the border of the screen, but the area where the color changes will probably "flicker" a bit, i.e. move randomly around in a small area. This is because we only check when the rasterLINE is right. Ideally, we would also want to check for the right "raster- coloumn" to be right, so that the cut could be at our specific (x,y) point, but unfortunately the c64 doesn't directly provide  such a rastercolumn register, so removing the flicker can be tricky business.
  180.  
  181. Of course there's much more to it than this. For instance, the  VIC provides a facility to automatically announce to the program when a certain rasterline arives, so that we needn't check the rastervalue ourselves in a loop. This technique is known as raster- interrupts, but I'll leave that subject to another time.
  182.  
  183. Until then, welcome in the world of rasters, and happy hacking!
  184.  
  185. (If you want more detailed information about advanced techniques, I would advice you to get the superb net-magazine called "C= Hacking". You can get this from various ftp-sites, including ftp.funet.fi).
  186.  
  187. -------------------------------- 
  188.  
  189. Stable Rasters
  190.  
  191. From : firefoot@netaxs.com
  192.  
  193.  
  194. LORDTYM@DELPHI.COM (LORDTYM@news.delphi.com) wrote:
  195.  
  196. :     Okay, with my great intellectual curiousity, I examined the code for a Fli viewer. This program used a version of the code Firefoot posted. I found many obvious occurences of bad coding in the viewer, but it left me with a certain wonder. 
  197.  
  198. Well, it's my code, so I feel inclined to comment:
  199.  
  200. First, you may think that code is "bad" but I would have to disagree,  that code was carefully crafted:  Not only does the FLI routine work on  both c64 and 128 (uncommon for FLI), but it times itself - the $d011  stores before you get to the actual screen time out exactly right, a  built-in 3 cycle tolerance is accounted for, and if the BPL insruction  crosses a page boundry and uses an extra cycle, the viewer still works  fine. I'll admit it's a bit unclear... :)
  201.  
  202. : How does it possibly work? It would seem that the inc $d011 instructions somehow 'trick' the Vic-II into doing something its not supposed to do.
  203.  
  204. Yes. You can also use $d011 to "push" the screen down (FLD), or to position the screen at any horizontal location (VSP). Rather powerful graphics effects, IMO. Also, ofcourse, FLI and all it's varients... most stunning graphics I've ever seen on 64. 
  205.  
  206. To see for example, FLD, check out Pyromania/Arson & What 'ya  got/Arson+FOE, to see VSP try umm... last page of Gold/Style (sorry), to  see FLI, well.. you have. (Those are all NTSC examples).
  207.  
  208. : The $d011 register is often referred to as the 'magic' register. I am beginning to think this is because nobody really knows the how or why it works.
  209.  
  210. Knows exactly how, down to being able to predict exactly what a piece of  $d011-containg code will do without actually running it?  No one, yet.  I kind of program $d011 by intuition...
  211.  
  212. : I wonder if some hacker didn't just stumble across the properties of this register.
  213.  
  214. I have no doubt some of the properties of $d011 were discovered by  accident. That they were made in to useable features of the VIC, I think  says something about the ability of the coders involved, not just "some  hackers".... :)
  215.  
  216. : The actual code does not appear to be timed except to start at exactly the same place each time. 
  217.  
  218. That is all that needs to be timed in the sense that you're thinking of. Manipulating $d011 carefully will cause the VIC to use (or not use) cycles (the VIC steals the processor for DMA at some points on the  display-screen), thus "timing" your code. For a good introduction to  this (but by no means a comprehensive explanation), try the VIC-II specs  in the back of the PRG, p448. I've been told by Marko that there is also a  theory of a complete description of $d011 in German, but I don't think  it's been translated... But to those of you out there who speak both  languages.... ? :)
  219.  
  220. : The inc $d011 instructions appear to be the timers and will wait until the current raster line is finished.
  221.  
  222. If it was my code, I used sta $d011, not inc $d011.... 
  223.  
  224. They don't "wait until the current raster line is finished", they are timed to occur. The previous sta $d011 caused the VIC to do a 40-cycle DMA (steals the processor for 40 cycles) on the current line. 
  225.  
  226. : In depth technical explanations, anyone?
  227.  
  228. Well, I tried to explain your questions above... still confused?
  229.  
  230. -------------------------- 
  231.  
  232. 6502? or 6510?
  233.  
  234. From : Jim Brain
  235.  
  236.   Joshua Dickerson wrote :
  237.  
  238. JD> I have a problem... Does the C64 run on 6502 or 6510? 
  239.  
  240. The 64 runs a 6510, which is a 6502 with special registers at location 0 and 1. Otherwise, the chips are functionally identical.
  241.  
  242. The JMP operand occurs if you do a jmp (xxFF), wher xx is any number. The result should be that the address gets loaded with xxFF:(xx+1)00, but the actual address is xxFF:xx00. Some call it a bug, some call it a feature. The 6502 was really only designed to do indirect and indirect indexed stuff in z-page, and the designers decided it WAS going to be zpage only. This bug is an outgrowth of that. 
  243.  
  244. -----------------------------
  245.  
  246.  
  247.